Skip to content

fix: keep the declared test() type when no test case class is bound - #26

Merged
MrPunyapal merged 1 commit into
pestphp:5.xfrom
webard:fix/bare-test-call-outside-bound-test-files
Nov 2, 2026
Merged

MrPunyapal merged 1 commit into
pestphp:5.xfrom
webard:fix/bare-test-call-outside-bound-test-files

Conversation

@webard

@webard webard commented Nov 2, 2026

Copy link
Copy Markdown
Contributor

Since v5.3.0 (#22), a bare test() is typed as the bound test case. Files that only global in()-less traits apply to (e.g. pest()->use(WithCachedRoutes::class)) fall back to plain PHPUnit\Framework\TestCase. Helper files that call test() (e.g. tests/Helpers.php with test()->postJson(...)) then report false method.notFound errors:

Call to an undefined method PHPUnit\Framework\TestCase::postJson().

Fix

Narrow test() only when a binding actually names a test case class. With trait-only or hook-only bindings, test() keeps Pest's declared TestCall|HigherOrderTapProxy, as in 5.2.2.

  • PestTestCaseType::resolveIfClassBound() is new. TestFunctionReturnTypeExtension and TestFunctionProxyMethodExtension now use it.
  • $this inference in closures is unchanged.
  • BoundTestCasePrivateMemberRule doesn't need changes, because it only checks $this inside closures and never sees a bare test().

Tests

The new tests/Fixtures/GlobalTraitBinding fixture has a global trait, a class binding and a hook-only chain:

  • In a helper file, test() keeps the declared type. Without the fix it fails with PHPUnit\Framework\TestCase.
  • In a class-bound file, test() still resolves to CustomTestCase.

Copilot AI balanced review requested due to automatic review settings November 2, 2026 06:45

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

No active review issues remain for the change preserving Pest’s declared test() return type when no test case class is bound.

No open issues 🎉

What changed in this PR

Fixes false undefined-method errors by preserving Pest’s declared test() return type when no test case class is bound. Explicit class bindings still narrow the type, and closure $this inference remains unchanged.

Changes:

  • Adds class-bound-only resolution while sharing existing class and trait resolution logic.
  • Updates bare test() return typing and todo() proxy handling to use the new resolver.
  • Adds regression fixtures covering global traits, hook-only bindings, and explicit class bindings.
File Description
tests/​Type/​GlobalTraitBindingTest.php Runs type assertions for unbound helpers and class-bound files.
tests/​Type/​global-trait-binding-extension.neon Configures analysis of the new fixtures.
tests/​GlobalTraitBindingTestCase.php Provides the fixture-specific type inference configuration.
tests/​Fixtures/​GlobalTraitBinding/​tests/​Pest.php Defines global trait, class, and hook-only bindings.
tests/​Fixtures/​GlobalTraitBinding/​modules/​Billing/​tests/​Helpers.php Asserts that helpers retain Pest’s declared return type.
tests/​Fixtures/​GlobalTraitBinding/​modules/​Billing/​tests/​Feature/​billing-test-function.php Asserts class-bound typing and trait method resolution.
src/​Type/​Pest/​TestFunctionReturnTypeExtension.php Narrows test() only when a class is bound.
src/​Type/​Pest/​TestFunctionProxyMethodExtension.php Applies the class-binding requirement to todo() proxy handling.
src/​Type/​Pest/​PestTestCaseType.php Adds class-bound-only resolution and extracts shared type construction.

Review effort: Balanced

@MrPunyapal MrPunyapal left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the fix and regression coverage.

@MrPunyapal
MrPunyapal merged commit a56d8e5 into pestphp:5.x Nov 2, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants